package com.applet.interceptor;

import com.applet.constant.JwtClaimsConstant;
import com.applet.context.AlibabaTTL;
import com.applet.properties.JwtProperties;
import com.applet.result.Result;
import com.applet.utils.JwtUtil;
import io.jsonwebtoken.Claims;
import lombok.extern.slf4j.Slf4j;
import org.apache.http.entity.ContentType;
import org.springframework.stereotype.Component;
import org.springframework.util.AntPathMatcher;
import org.springframework.util.StringUtils;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 *  C端  全局拦截器
 *  需要拦截的资源需要在 SpringMvcConfig.java 中配置
 */
@Slf4j
@Component
public class GlobalInterceptor implements HandlerInterceptor {


    // mvc路径匹配器
    private static final AntPathMatcher PATH_MATCHER = new AntPathMatcher();

    //需要放行的路径  Swagger、登录接口、登出接口、店铺营业状态
    String[] urls = {"/swagger-ui.html", "/webjars/**", "/swagger-resource/**", "/swagger-resource", "/v2/**", "/csrf",
                     "/user/user/login", "/user/shop/status", "/user/shop/status"};

    //注入工具实体bean
    @Resource
    private JwtProperties jwtProperties;

    //方法执行前执行
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        //设置响应的数据格式为json
        response.setContentType(ContentType.APPLICATION_JSON.toString());

        // 1.获取当前请求路径
        String requestURI = request.getRequestURI();
        log.info("GlobalInterceptor - 当前请求路径url: {}", requestURI);

        // 2.检验是否需要放行
        Boolean flag = checkUrl(urls, requestURI);


        // 3.判断校验结果
        if(flag){
            log.info("GlobalInterceptor - 当前路径:{} 需要放行", requestURI);
            //放行 并结束方法
            return true;
        }

        // 4.不放行,请求头中获取authentication
        String jwtToken = request.getHeader(jwtProperties.getUserTokenName());

        // 5.判断token是否为空
        if( !StringUtils.hasLength(jwtToken) ){
            log.info("拦截器-当前资源路径:{}, 需要校验,但token为空,请先登录", requestURI);
            //封装token错误信息 返回
            Result<Object> error = Result.error("拦截器-token为空，请先登录");
            response.getWriter().println(error);
            //不放行 且 结束方法
            return false;
        }


        // 6.替换Token中的"Bearer "
        String token = jwtToken.replace("Bearer ", "");

        // 7.解析token 是否抛异常？
        try {
            Claims claims = JwtUtil.parseJWT(jwtProperties.getUserSecretKey(), token);
            Long userId = Long.valueOf(claims.get(JwtClaimsConstant.USER_ID).toString());
            log.info("拦截器-token解析,用户id: {},存入threadLocal ", userId);
            AlibabaTTL.threadLocalSet(userId);
        } catch (Exception e) {
            log.info(requestURI + " --拦截器-token令牌解析异常");
            //封装token解析错误异常信息 返回
            Result<Object> error = Result.error("拦截器-token解析异常，请重新登录");
            response.getWriter().println(error);
            //不放行 且 结束
            return false;
        }

        // 8.已登录，放行
        log.info("GlobalInterceptor - " + requestURI + " - 令牌合法，放行");
        return true;
    }

    //比较当前请求路径是否需要放行
    private Boolean checkUrl(String[] urls, String requestURI) {
        for (String url : urls) {
            boolean flag = PATH_MATCHER.match(url, requestURI);
            if(flag){
                return true;
            }
        }
        return false;
    }


    //方法执行后执行
    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        System.out.println("GlobalInterceptor - postHandle()");
    }

    //视图渲染完毕后，最后执行
    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        System.out.println("GlobalInterceptor - afterCompletion()");
        //请求完成后，移除掉线程变量副本保存的值，防止内存泄漏
        AlibabaTTL.threadLocalRemove();
    }
}
